﻿using System;
using System.Windows.Forms;

namespace Xompare
{
    using CLAP;

    using FormsUtilities;

    using Utilities.FileChangesTracking;

    using Xompare.Helpers;

    public partial class MdiContainer : Form
    {
        public MdiContainer()
        {
            InitializeComponent();

            RegisterUiItems();
            InitializeUiCommands();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var aboutForm = new AboutForm();

            aboutForm.ShowDialog();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void newFileComparisonToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var fileDialog = new OpenFileDialog { Title = "Choose the original XML file" };

            CreateFileDiffTab(
                () =>
                {
                    fileDialog.ShowDialog();

                    return new NameAndLabel(fileDialog.FileName, null);
                },
                () =>
                {
                    fileDialog.FileName = string.Empty;
                    fileDialog.Title = "Choose the target XML file";
                    fileDialog.ShowDialog();

                    return new NameAndLabel(fileDialog.FileName, null);
                });
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (mdiChildTabs.TabCount > 0)
            {
                var tabBehavior = mdiChildTabs.SelectedTab as ITabPageBehavior;
                if (tabBehavior != null)
                {
                    tabBehavior.OnRemoval(mdiChildTabs.TabCount == 1);
                }

                mdiChildTabs.TabPages.Remove(mdiChildTabs.SelectedTab);

                if (mdiChildTabs.TabCount == 0)
                {
                    UiCommand.GetUiCommand(UiCommandNames.TabCommon).Enabled = false;
                    UiCommand.GetUiCommand(UiCommandNames.TabCloseAllButThis).Enabled = mdiChildTabs.TabCount != 1;
                }
            }
        }

        #region Helper utilties

        /// <summary>
        /// Create a new tab with XML files comparator.
        /// </summary>
        /// <param name="getOriginalFilePath">A func to get the original XML file path.</param>
        /// <param name="getTargetFilePath">A func to get the target XML file path.</param>
        public void CreateFileDiffTab(Func<NameAndLabel> getOriginalFilePath, Func<NameAndLabel> getTargetFilePath)
        {
            var newComparisonTabPage = new XmlComparisonTabPage("New comparison");

            if (newComparisonTabPage.AttachXmlComparison(
                getOriginalFilePath,
                getTargetFilePath,
                UiCommand.GetUiCommand(UiCommandNames.IgnoreNameCase).Checked,
                UiCommand.GetUiCommand(UiCommandNames.IgnoreValueCase).Checked,
                UiCommand.GetUiCommand(UiCommandNames.IgnoreWhiteSpaces).Checked))
            {
                mdiChildTabs.TabPages.Add(newComparisonTabPage);
                mdiChildTabs.SelectedTab = newComparisonTabPage;

                string newTitle = mdiChildTabs.SelectedTab == null ? null : mdiChildTabs.SelectedTab.Text;

                Controller.SetApplicationTitle(newTitle);
                UiCommand.GetUiCommand(UiCommandNames.TabCommon).Enabled = true;
                UiCommand.GetUiCommand(UiCommandNames.TabCloseAllButThis).Enabled = mdiChildTabs.TabCount != 1;
                UiCommand.GetUiCommand(UiCommandNames.TabXmlComparison).Visible = true;
            }
        }

        /// <summary>
        /// Registers all UI tool-items so they are later controlled by the application flow.
        /// </summary>
        private void RegisterUiItems()
        {
            UiCommand.RegisterUiToolItem(UiCommandNames.NewComparison, toolButtonNewComparison);
            UiCommand.RegisterUiToolItem(UiCommandNames.NewComparison, newFileComparisonToolStripMenuItem);

            UiCommand.RegisterUiToolItem(UiCommandNames.ViewXmlSyntax, toolButtonViewWithXml);
            UiCommand.RegisterUiToolItem(UiCommandNames.ViewXmlSyntax, withXMLSyntaxToolStripMenuItem);
            UiCommand.SetUiCommandCheckable(UiCommandNames.ViewXmlSyntax);

            UiCommand.RegisterUiToolItem(UiCommandNames.IgnoreNameCase, toolButtonIgnoreNameCase);
            UiCommand.RegisterUiToolItem(UiCommandNames.IgnoreNameCase, ignoreNameCaseToolStripMenuItem);
            UiCommand.SetUiCommandCheckable(UiCommandNames.IgnoreNameCase);

            UiCommand.RegisterUiToolItem(UiCommandNames.IgnoreValueCase, toolButtonIgnoreValueCase);
            UiCommand.RegisterUiToolItem(UiCommandNames.IgnoreValueCase, ignoreValueCaseToolStripMenuItem);
            UiCommand.SetUiCommandCheckable(UiCommandNames.IgnoreValueCase);

            UiCommand.RegisterUiToolItem(UiCommandNames.IgnoreWhiteSpaces, toolButtonIgnoreValueWhiteSpace);
            UiCommand.RegisterUiToolItem(UiCommandNames.IgnoreWhiteSpaces, ignoreWhiteSpacesToolStripMenuItem);
            UiCommand.SetUiCommandCheckable(UiCommandNames.IgnoreWhiteSpaces);

            UiCommand.RegisterUiToolItem(UiCommandNames.TabCommon, toolButtonRefresh);
            UiCommand.RegisterUiToolItem(UiCommandNames.TabCommon, refreshToolStripMenuItem);
            UiCommand.RegisterUiToolItem(UiCommandNames.TabCommon, closeToolStripMenuItem);
            UiCommand.RegisterUiToolItem(UiCommandNames.TabCommon, closeDocumentToolStripMenuItem);
            UiCommand.RegisterUiSubCommand(UiCommandNames.TabXmlComparison, UiCommandNames.IgnoreNameCase);
            UiCommand.RegisterUiSubCommand(UiCommandNames.TabXmlComparison, UiCommandNames.IgnoreValueCase);
            UiCommand.RegisterUiSubCommand(UiCommandNames.TabXmlComparison, UiCommandNames.IgnoreWhiteSpaces);
            UiCommand.RegisterUiToolItem(UiCommandNames.TabXmlComparison, toolStripXmlComparisonSeparator);
/* TODO: Add back when the view is ready to show the tree as XML view
            UiCommand.RegisterUiSubCommand(UiCommandNames.TabXml, UiCommandNames.ViewXmlSyntax);
            UiCommand.RegisterUiToolItem(UiCommandNames.TabXml, toolStripViewSeparator);
            UiCommand.RegisterUiSubCommand(UiCommandNames.TabXmlComparison, UiCommandNames.TabXml);
*/
            UiCommand.RegisterUiToolItem(UiCommandNames.TabXmlComparison, viewToolStripMenuItem); // TODO: Remove once the 'View' menu has more items.

            UiCommand.ActOnUiCommand(UiCommandNames.IgnoreNameCase, uiItem => uiItem.Click += OnIgnoreNameCase);
            UiCommand.ActOnUiCommand(UiCommandNames.IgnoreValueCase, uiItem => uiItem.Click += OnIgnoreValueCase);
            UiCommand.ActOnUiCommand(UiCommandNames.IgnoreWhiteSpaces, uiItem => uiItem.Click += OnIgnoreWhiteSpaces);
            UiCommand.ActOnUiCommand(UiCommandNames.ViewXmlSyntax, uiItem => uiItem.Click += OnViewXmlSyntax);

            UiCommand.RegisterUiToolItem(UiCommandNames.TabCloseAllButThis, closeAllButThisToolStripMenuItem);

            // Configuration apply:
            var xmlComparisonConfigElement = Controller.ConfigInfo.GuiDefinitionConfig.XmlComparisonTabConfig;

            UiCommand.GetUiCommand(UiCommandNames.IgnoreNameCase).Checked = xmlComparisonConfigElement.IgnoreNameCase;
            UiCommand.GetUiCommand(UiCommandNames.IgnoreValueCase).Checked = xmlComparisonConfigElement.IgnoreValueCase;
            UiCommand.GetUiCommand(UiCommandNames.IgnoreWhiteSpaces).Checked = xmlComparisonConfigElement.IgnoreWhiteSpaces;

            UiCommand.GetUiCommand(UiCommandNames.ViewXmlSyntax).Checked = Controller.ConfigInfo.GuiDefinitionConfig.XmlTabConfig.ViewXmlSyntax;
        }

        /// <summary>
        /// Initializes the UI commands's state, other than their default.
        /// </summary>
        private void InitializeUiCommands()
        {
            UiCommand.GetUiCommand(UiCommandNames.TabCommon).Enabled = false;
            UiCommand.GetUiCommand(UiCommandNames.TabXmlComparison).Visible = false;
        }

        private void OnViewXmlSyntax(object sender, EventArgs e)
        {
            var xmlComparisonTab = mdiChildTabs.SelectedTab as IXmlTabPage;

            if (xmlComparisonTab != null)
            {
                bool newValue = UiCommand.GetUiCommand(UiCommandNames.ViewXmlSyntax).Checked;

                xmlComparisonTab.OnViewXmlSyntax(newValue);

                Controller.ConfigInfo.GuiDefinitionConfig.XmlTabConfig.ViewXmlSyntax = newValue;
                Controller.SaveConfiguration();
            }
        }

        private void OnIgnoreNameCase(object sender, EventArgs e)
        {
            var xmlComparisonTab = mdiChildTabs.SelectedTab as IXmlComparisonTabPage;

            if (xmlComparisonTab != null)
            {
                bool newValue = UiCommand.GetUiCommand(UiCommandNames.IgnoreNameCase).Checked;

                xmlComparisonTab.OnIgnoreNameCaseChange(newValue);

                Controller.ConfigInfo.GuiDefinitionConfig.XmlComparisonTabConfig.IgnoreNameCase = newValue;
                Controller.SaveConfiguration();
            }
        }

        private void OnIgnoreValueCase(object sender, EventArgs e)
        {
            var xmlComparisonTab = mdiChildTabs.SelectedTab as IXmlComparisonTabPage;

            if (xmlComparisonTab != null)
            {
                bool newValue = UiCommand.GetUiCommand(UiCommandNames.IgnoreValueCase).Checked;

                xmlComparisonTab.OnIgnoreValueCaseChange(newValue);

                Controller.ConfigInfo.GuiDefinitionConfig.XmlComparisonTabConfig.IgnoreValueCase = newValue;
                Controller.SaveConfiguration();
            }
        }

        private void OnIgnoreWhiteSpaces(object sender, EventArgs e)
        {
            var xmlComparisonTab = mdiChildTabs.SelectedTab as IXmlComparisonTabPage;

            if (xmlComparisonTab != null)
            {
                bool newValue = UiCommand.GetUiCommand(UiCommandNames.IgnoreWhiteSpaces).Checked;

                xmlComparisonTab.OnIgnoreWhiteSpacesChange(newValue);

                Controller.ConfigInfo.GuiDefinitionConfig.XmlComparisonTabConfig.IgnoreWhiteSpaces = newValue;
                Controller.SaveConfiguration();
            }
        }

        #endregion

        private void cLISyntaxToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LogUi.LogInfo(Controller.CliHelpMessage);
        }

        private void MdiContainer_Load(object sender, EventArgs e)
        {
            // Create help message for CLI syntax menu:
            Parser.Run<XompareCliParser>(new string[0]);

            // Parse CLI arguments if needed:
            if (Controller.CliArguments.Length > 0)
            {
                if (Parser.RunWinForms<XompareCliParser>(Controller.CliArguments) != 0)
                {
                    Environment.Exit(1);
                }
            }
        }

        private void mdiChildTabs_Selected(object sender, TabControlEventArgs e)
        {
            if (e.TabPage == null)
            {
                Text = Application.ProductName;
            }
            else
            {
                Controller.SetApplicationTitle(e.TabPage.Text);

                // If this is an XML comparator tab - refresh if needed:
                var xmlComparisonTab = e.TabPage as IXmlComparisonTabPage;

                if (xmlComparisonTab != null)
                {
                    xmlComparisonTab.SoftRefreshTab(
                        UiCommand.GetUiCommand(UiCommandNames.IgnoreNameCase).Checked,
                        UiCommand.GetUiCommand(UiCommandNames.IgnoreValueCase).Checked,
                        UiCommand.GetUiCommand(UiCommandNames.IgnoreWhiteSpaces).Checked);
                }
            }
        }

        private void toolButtonRefresh_Click(object sender, EventArgs e)
        {
            if (mdiChildTabs.TabPages.Count > 0)
            {
                var tabBehavior = mdiChildTabs.SelectedTab as ITabPageBehavior;

                if (tabBehavior == null)
                {
                    throw new InvalidOperationException("A tab page has to implement 'ITabPageBehavior'");
                }

                tabBehavior.RefreshTabPage();
            }
        }

        private void closeAllDocumentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (var page in mdiChildTabs.TabPages)
            {
                var pageBehavior = page as ITabPageBehavior;

                if (pageBehavior != null)
                {
                    pageBehavior.OnRemoval(true);
                }
            }

            mdiChildTabs.TabPages.Clear();

            UiCommand.GetUiCommand(UiCommandNames.TabCommon).Enabled = false;
        }

        private void closeAllButThisToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (var item in mdiChildTabs.TabPages)
            {
                var page = item as TabPage;

                if (page != null && page != mdiChildTabs.SelectedTab)
                {
                    var pageBehavior = page as ITabPageBehavior;

                    if (pageBehavior != null)
                    {
                        pageBehavior.OnRemoval(false);
                    }

                    mdiChildTabs.TabPages.Remove(page);
                }
            }

            UiCommand.GetUiCommand(UiCommandNames.TabCloseAllButThis).Enabled = false;
        }

        private void MdiContainer_Activated(object sender, EventArgs e)
        {
            FileChangeTrackingManager.NotifySubscribers();
        }

        private void MdiContainer_KeyDown(object sender, KeyEventArgs e)
        {
            Controller.IsControlPressed = e.Control;
        }

        private void MdiContainer_KeyUp(object sender, KeyEventArgs e)
        {
            Controller.IsControlPressed = e.Control;
        }
    }
}
